package com.design.reactor.stretchIO._1_singleReactorSingleThread.impl;

import com.design.reactor.stretchIO._1_singleReactorSingleThread.impl.handler.AcceptHandler;
import com.design.reactor.stretchIO._1_singleReactorSingleThread.impl.handler.Handler;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * SocketChannel / ServerSocketChannel : 句柄或描述符 ,就是资源
 * SelectionKey ：就是资源事件
 * <p>
 * Selector 是同步事件分离器，selector.select() 就是等待事件发生的阻塞方法
 * Reactor.dispatcher() : 就是 初始分发器
 * <p>
 * SocketChannel / ServerSocketChannel.register(selector,SelectionKey.XXX) :  把什么资源的事件 注册到 Selector 上
 * <p>
 * AbstractHandler ：抽象事件处理器
 * AcceptHandler / ReaderHandler / WriterHandler : 具体的事件处理器
 */
public class Reactor implements Runnable {
    final Selector selector;
    final ServerSocketChannel serverSocketChannel;

    /**
     * reactor 1: 初始设置
     */
    Reactor(int port) throws IOException {
        System.out.println("---- Reactor 构造函数 ----");
        selector = Selector.open();
        serverSocketChannel = ServerSocketChannel.open();
//        serverSocketChannel.socket().bind(new InetSocketAddress(port));
        serverSocketChannel.bind(new InetSocketAddress(port));
        new AcceptHandler(selector, serverSocketChannel);
    }

    /**
     * Selector 是同步事件分离器，selector.select() 就是等待事件发生的阻塞方法
     */
    @Override
    public void run() {
        try {
            System.out.println("----Reactor.run() 的线程名 : " + Thread.currentThread().getName() + "\n");
            while (!Thread.interrupted()) {//获取注册事件
                selector.select(); //这个方法是阻塞方法 ，而selector.wakeup()会唤醒阻塞中的selector
                Set<SelectionKey> sks = selector.selectedKeys();
                Iterator<SelectionKey> it = sks.iterator();

                while (it.hasNext()) {
                    SelectionKey selectionKey = it.next();
                    dispatcher(selectionKey);//分发每一个请求
                }
                // 也可以在while循环中使用iterator的remove方法
                sks.clear();

            }
        } catch (IOException ignored) {
            // ignored
        }
    }

    /**
     * 初始分发器
     *
     */
    private void dispatcher(SelectionKey selectionKey) throws IOException {
        Selector selector = selectionKey.selector();
        SelectableChannel channel = selectionKey.channel();
        Handler handler = (Handler) selectionKey.attachment();//获取之前绑定的对象
        if (null != handler) {
            handler.handle(selector, channel, selectionKey);
        }
    }

    public static void main(String[] args) throws Exception {
        Reactor reactor = new Reactor(8899);
        new Thread(reactor).start();//这就是 reactor 线程 服务端线程
    }
}
